# Copyright 2024 Henrique Paone
#
# This file is part of Kitty-Visual.
#
# Kitty-Visual is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
# 
# Kitty-Visual is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License along with
# Kitty-Visual. If not, see <https://www.gnu.org/licenses/>.

class Nvim
  @@config = '~/.config/kitty/kitty-visual/kitty-visual.vim'
  @@root = "#{ Dir.tmpdir }/.kitty-visual"
  @@ready_file = "#{ @@root }/startup"
  
  attr_reader :pid, :nvim, :root, :scrollback

  def initialize()
    Dir.mkdir(@@root) unless Dir.exist? @@root
    @server = gen_server_name
    args = "-RM --headless --listen #{ @server } -S #{ @@config }"
    ENV['VIMRUNTIME'] = '/usr/share/nvim/runtime/'
    @pid = spawn "nvim #{ args } &> /dev/null"
    ready?
    @nvim = MessagePack::RPC::Client.new(MessagePack::RPC::UNIXTransport.new, @server)
  end

  def method_missing(m, *args, &block)
    begin
      @nvim.call(m.to_s.prepend('nvim_').to_sym, *args)
    rescue MessagePack::RPC::RuntimeError => e
      begin 
        @nvim.call(:nvim_call_function, m, args)
      rescue MessagePack::RPC::RuntimeError => e
        @nvim.call(m, *args)
      end
    end
  end

  def scrollback=(scrollback)
    @scrollback = scrollback
    temp = Tempfile.new('scrollback-noansi', "#{ @@root }")
    temp.write scrollback.join("\n")
    temp.close
    command "e #{ temp.path }"
  end
  
  def gen_server_name()
    servers = Dir["#{ @@root }/nvim.kitty-visual*"]
    server_name = 'nvim.kitty-visual-' + (servers.empty? ? '1' : "#{ servers.max[-1].next }")
    "#{ @@root }/#{ server_name }"
  end

  def ready?
    loop do
      if File.exist? @@ready_file 
        File.delete @@ready_file
        break 
      end
    end
  end

  def call(func, *args)
    if args.empty?
      @nvim.call(func)
    else @nvim.call(func, *args)
    end
  end

  def get_bg_color(group)
    synIDattr(synIDtrans(hlID(group)), 'bg#')
  end

  def get_selection
    ctrl_v = "\u0016"
    
    _, lbeg, cbeg, _ = getpos('v')
	_, lend, cend, _ = getpos('.')
	lines_content = getline(lbeg, lend)
	
	# In case selection goes upward
	if lines_content.empty?
		lbeg, lend = lend, lbeg
		cbeg, cend = cend, cbeg
		lines_content = getline(lbeg, lend)
	end

    line_nums = *(lbeg..lend)
    lines = {}
    line_nums.each_with_index do |_, i| lines[line_nums[i]] = lines_content[i] end

	hi_lines = []
	
	# Different strategies for each mode
    case get_mode()['mode']
      when 'v'
		lfirst = lines[lines.keys.min]
		llast = lines[lines.keys.max]
        lines.keys.each do |l|
			cstart = 0
			cstop = lines[l].size
			cstart = cbeg if lines[l] == lfirst
            cstop = cend if lines[l] == llast
			cstart, cstop = cstop, cstart if cstart > cstop
            hi_lines << [l, cstart, cstop]
		end
      when 'V'
        lines.keys.each do |l|
          cstart = 0
          cstop = lines[l].size
		  cstart, cstop = cstop, cstart if cstart > cstop
          hi_lines << [l, cstart, cstop]
        end
      when ctrl_v
		cstart = cbeg
		cstop = cend
        lines.keys.each do |l|
          cstart, cstop = cstop, cstart if cstart > cstop
          hi_lines << [l, cstart, cstop]
		end
      else raise "Can't get selection, not in visual mode"
    end
	hi_lines
  end
  
  private :ready?
end

